package com.ytktt.study.week9.task3.rpcfx.client.transport.netty;

import com.ytktt.study.week9.task3.rpcfx.api.RpcfxRequest;
import com.ytktt.study.week9.task3.rpcfx.api.RpcfxResponse;
import com.ytktt.study.week9.task3.rpcfx.client.transport.RpcfxTransport;
import com.ytktt.study.week9.task3.rpcfx.server.netty.coder.FastJsonDecoder;
import com.ytktt.study.week9.task3.rpcfx.server.netty.coder.FastJsonEncoder;
import com.ytktt.study.week9.task3.rpcfx.server.netty.coder.ProtostuffDecoder;
import com.ytktt.study.week9.task3.rpcfx.server.netty.coder.ProtostuffEncoder;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.*;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;

import java.net.URI;

/**
 * TODO
 *
 * @author ytk
 */
public class NettyTransport implements RpcfxTransport {

    private final EventLoopGroup group = new NioEventLoopGroup();

    @Override
    public RpcfxResponse transport(RpcfxRequest req, String url, Class<?> returnType) throws Exception {
        URI uri = new URI(url);
        NettyClientHandler handler = new NettyClientHandler();

        Bootstrap b = new Bootstrap();
        b.group(group)
                .channel(NioSocketChannel.class)
                .handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel ch) throws Exception {
                        ChannelPipeline p = ch.pipeline();
                        p.addLast(new ProtostuffEncoder(RpcfxRequest.class));
                        p.addLast(new ProtostuffDecoder(RpcfxResponse.class));
                        p.addLast(new LoggingHandler(LogLevel.INFO));
                        p.addLast(handler);
                    }
                });

        ChannelFuture channelFuture = b.connect(uri.getHost(), uri.getPort()).sync();
        channelFuture.channel()
                .writeAndFlush(req)
                .sync();

        return handler.getResult();
    }

    @Override
    public void clear() {
        this.group.shutdownGracefully();
    }
}
